#include <stdio.h>
//预处理详解
//1️⃣预定义符号
int main()
{
    printf("%s\n",__FILE__);//进行编译的源文件名
    printf("%d\n",__LINE__);//文件当前的行号
    printf("%s\n",__DATE__);//文件被编译的日期
    printf("%s\n",__TIME__);//文件被编译的时间
    printf("%d\n",__STDC__);//如果编译器遵循ANSI C，其值为1，否则未定义
    return 0;
}
//输出：
//Y:\code\C\41.c
//7
//Jun 16 2025
//19:10:41
//1
//2️⃣#define 定义常量        vscode 3.c
//①
#define reg register
int main()
{
    reg int num;//建议将num中的值存放到寄存器中，但最后是由编译器决定放不放 P33
    return 0;
}
//②
#define do_forever for(;;)
int main()
{
    do_forever; //死循环
    //for(;;)
    //   ;    这个;相当于循环体(空语句) P45
    return 0;
}
//③
#define CASE break;case
int main()
{
    int i=1;
    switch(i)
    {
        /*
        case 1:
        break;
        case 2:
        break;
        case 0:
        break;
        default:
        break;
        */
       case 1:
       CASE 2:
       CASE 0:
       break;
       default:
       break;
    }
    return 0;
}
//④定义的stuff过长，可以分成几行写，除了最后一行外，每行的末尾都加一个反斜杠（续行杠）
#define DEBUG_PRINT printf("file:%s\tline:%d   \
date:%s\ttime:%s\n",\
                    __FILE__,__LINE__,\
                    __DATE__,__TIME__)
int main()
{
    DEBUG_PRINT;//file:Y:\code\C\41.c     line:69   date:Jun 16 2025      time:20:45:52
    return 0;
}
//注意空格：要让line:%d和date:%s之间有空格，既可以在%d后面加，也可以在date前面加。
//3️⃣#define 定义宏          vscode 3.c
//①带有副作用的宏参数：
//例题：写一个宏，求两个数的较大值
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
    int x=10;
    int y=20;
    int r=MAX(x++,y++);
//  int r=((x++)>(y++)?(x++):(y++))  解析P157
    printf("x=%d y=%d r=%d",x,y,r);//x=11 y=22 r=21
    return 0;
}
//②宏和函数对比
//例题：求两个数的较大值 P158
//宏的实现方式：（更有优势）
#define MAX(a,b) ((a)>(b)?(a):(b))
//函数的实现方式：
int Max(int a,int b)
{
    return a>b?a:b;
}
int main()
{  
    int x=10;
    int y=20;
    int r1=MAX(x,y);//预处理后：int r1=((x)>(y)?(x):(y));
    printf("r1=%d\n",r1);//r1=20
    int r2=Max(x,y);//预处理后：int r2=Max(x,y);
    printf("r2=%d\n",r2);//r2=20
    return 0;
}
//宏的参数可以出现类型：
#include <stdlib.h>
#define MALLOC(num,type) (type *)malloc(num*sizeof(type))
int main()
{
    //下面两种写法等价：
    int *a=(int *)malloc(10*sizeof(int));
    int *b=MALLOC(10,int);
    return 0;
}
//4️⃣#和##
//①#运算符
int main()
{
    printf("hello world\n");    //hello world
    printf("hello""world\n");   //helloworld
    printf("hello"   "world\n");//helloworld
    printf("hello"" world\n");  //hello world
    return 0;
}//向上面那样写多个字符串"xxx""xxx"就会合并成一个字符串"xxxxxx"
//例题引入：
#define PRINTF(n,format) printf("the value of n is "format"\n",n)
int main()
{
    int a=10;
    PRINTF(a,"%d");//the value of n is 10
    float b=3.14f;
    PRINTF(b,"%f");//the value of n is 3.140000
    return 0;
} 
#define PRINTF(n,format) printf("the value of "#n" is "format"\n",n)
int main()
{
    int a=10;
    PRINTF(a,"%d");//the value of a is 10
    float b=3.14f;
    PRINTF(b,"%f");//the value of b is 3.140000
    return 0;
} 
//例题巩固：
int main()
#define PRINT(a) printf("the value of "#a" is %u\n",sizeof(a));
int main()
{
    int n=10;
    PRINT(n);
    printf("the value of n is %u\n",sizeof(n));
    return 0;
}
//输出：
//the value of n is 4
//the value of n is 4
//②##运算符
//例题：写一个函数求2个数的较大值时，不同的数据类型就得写不同的函数，如下：
int int_max(int x,int y)
{
    return x>y?x:y;
}
float float_max(float x,float y)
{
    return x>y?x:y;
}
int main()
{
    int a=10;
    int b=20;
    printf("%d\n",int_max(a,b));//20
    float m=6.6f;
    float n=8.8f;
    printf("%f\n",float_max(m,n));//8.800000
    return 0;
}
//上面的写法太繁琐，用##运算符可简化：
#define GENERIC_MAX(type) type type##_max(type x,type y)\
{return x>y?x:y;}
//这个相当于函数的定义：
GENERIC_MAX(int)       //替换到宏体内后int##_max生成了新的符号int_max做函数名
//预处理后：int int_max(int x,int y){return x>y?x:y;}
GENERIC_MAX(float)     //替换到宏体内后float##_max生成了新的符号float_max做函数名
//预处理后：float float_max(float x,float y){return x>y?x:y;}
int main()
{
    int a=10;
    int b=20;
    printf("%d\n",int_max(a,b));//20
    float m=6.6f;
    float n=8.8f;
    printf("%f\n",float_max(m,n));//8.800000
    return 0;
}
//5️⃣#undef
//如果现存的一个名字需要被重新定义，那么它的旧名字首先要被移除。
#define M 100
int main()
{
    printf("%d\n",M);//100
#undef M
    //printf("%d\n",M);   这里会报错：标识符M没有被声明
#define M 50
    printf("%d\n",M);//50
    return 0;
}
//6️⃣条件编译
//1.调试性的代码，删除可惜，保留又碍事，所以我们可以选择性的编译。
#define __DEBUG__
int main()
{
    int i = 0;
    int arr[10] = {0};
    for(i = 0; i < 10; i++)
    {
    arr[i] = i;
    #ifdef __DEBUG__
    printf("%d\n", arr[i]);//为了观察数组是否赋值成功。
    #endif //将#define __DEBUG__这句注释掉，就不会打印了
    }
    return 0;
}
//2.常见的条件编译指令
//①单分支的条件编译
int main()
{
    #if 0
    printf("hehe"); //不会打印（常量表达式为假）
    #endif
    return 0;
}
int main()
{
    #if 2>1
    printf("hehe"); //输出：hehe（常量表达式为真）
    #endif
    return 0;
}
int main()
{
    int a=10;//变量
    #if a
    printf("hehe"); //不会打印（不是常量表达式）
    #endif
    return 0;
}
//②多分支的条件编译
#define M 100
int main()
{
    #if M==0
    printf("hehe");
    #elif M>10
    printf("haha");//输出：haha
    #elif M==100
    printf("呵呵");
    #else
    printf("哈哈");
    #endif
    return 0;
}
//③判断是否被定义
//只要定义了就参与编译：
#define M 0    //只要被定义就为真，即使定义成0值
int main()
{

    #ifdef M  //等价于 #if defined(M)
    printf("hehe");//输出：hehe
    #endif
    return 0;
}
//#define M 100
int main()
{
    #if defined(M)
    printf("hehe");//不会打印
    #endif
    return 0;
}
//没有定义才参与编译：
//#define M 100    
int main()
{
    #ifndef M  //等价于 #if !defined(M)
    printf("hehe");//输出：hehe
    #endif
    return 0;
}
#define M 100
int main()
{
    #if !defined(M)
    printf("hehe");//不会打印
    #endif
    return 0;
}
//④嵌套指令
#if defined(OS_UNIX)
    #ifdef OPTION1
        unix_version_option1();
    #endif
    #ifdef OPTION2
        unix_version_option2();
    #endif
#elif defined(OS_MSDOS)
    #ifdef OPTION2
        msdos_version_option2();
    #endif
#endif